home *** CD-ROM | disk | FTP | other *** search
/ Freaks Macintosh Archive / Freaks Macintosh Archive.bin / Freaks Macintosh Archives / Textfiles / HowToBeASerialKiller.txt < prev    next >
Text File  |  1996-08-22  |  14KB  |  272 lines

  1.                     HOW TO BECOME A SERIAL KILLER
  2.                     
  3. (A Hacker's Guide to Reverse Engineering Serial Number Algorithms)
  4.  
  5.                           by =-BOOK-WORM->
  6. -----------------------------------------------------------------------
  7. If you've ever cracked an application before, you can understand the thrill of the quest, but if you've gone as far as figuring out how serial numbers can be generated, it puts you more into the mind frame of a secret agent, code breaking for the FBI.  In some cases it truly presents some of the toughest puzzles you'll ever encounter (except for perhaps, the "Rubik's Cube").  There is only one quality that is a must-have here....DETERMINATION!  I can not stress that enough.  If you're not willing to put some time into it, stop reading right now!  So the magic word for today folks is??? - DETERMINATION!!!
  8.  
  9. My intentions for writing this article are to provide steps and examples for those who already possess the following skills:
  10.  
  11. - Knowledge in using a debugger (My favorites in order: TMON, Jasik's, MacsBug)
  12. - Macintosh 68k assembler (As long as you have a manual, you should be OK)
  13. - Bitwise operations (OR, AND, XOR, etc...)
  14. - Basic Algebra (Ha!  And you thought you'd never use it!)
  15. - Determination (The magic word)
  16.  
  17. (Skills in operating a printer, doodling on paper, etc... are already assumed.)
  18.  
  19. I will be using "sn" to refer to serial number, registration code, etc... throughout this text.
  20.  
  21.  
  22.  
  23. THE FOUR QUESTIONS
  24. ==================
  25.  
  26. Only four questions need to be answered in solving each case:
  27.  
  28. 1. Where is it?
  29. 2. What does it do?
  30. 3. How can it be reversed?
  31. 4. Do the generated numbers work?
  32.  
  33. Knowing this, we will explore each question in detail.
  34.  
  35.  
  36.  
  37. 1. WHERE IS IT?
  38. ===============
  39.  
  40. Finding the routine can often be a challenge.  Luckily, the _GetIText trap will solve this question for you more often than not.  In most cases, each field in the dialog box will have a separate _GetIText issued to retrieve its contents.  The following technique can be used in these instances:
  41.  
  42. Technique 1
  43. -----------
  44. * Get to the application's registration screen
  45. * Enter debugger
  46. * Set a trap for _GetIText
  47. * Exit the debugger
  48. * Type something in all non-sn fields
  49. * Type "1234567890" into the sn field
  50. * Press "OK" (or equivalent)
  51. (At this point you should enter the debugger.  If not, read further for other techniques.)
  52. * View the contents of the area pointed to by register A1
  53. * If it contains "1234567890", start single stepping
  54. * If it does not, continue execution until it does, then start single stepping
  55.  
  56. When starting to learn, you should single step the entire way from this point.  As you become more experienced, you'll learn time saving skills by identifying specific library routines like "pascal to C string" functions which you may simply jump over.
  57.  
  58. In more challenging situations where _GetIText is not used, you may need to trap _TEKey.  If pressing the return key is permitted in lieu of the mouse click to accept the input, use:
  59.  
  60. Technique 2
  61. -----------
  62. * Get to the application's registration screen
  63. * Type something in all non-sn fields
  64. * Type "1234567890" into the sn field
  65. * Enter debugger
  66. * Set a trap for _TEKey
  67. * Exit the debugger
  68. * Press return
  69. (At this point you should enter the debugger)
  70. * Start single stepping
  71.  
  72. If a mouse click is needed to accept the input, use:
  73.  
  74. Technique 3
  75. -----------
  76. * Get to the application's registration screen
  77. * Type something in all non-sn fields
  78. * Type "123456789" into the sn field
  79. * Enter debugger
  80. * Set a trap for _TEKey
  81. * Exit the debugger
  82. * Type "0"
  83. (At this point you should enter the debugger)
  84. * Start single stepping
  85.  
  86. Each case is different.  In some cases, the developer may be generating a checksum "as you type" and therefore Techniques 2 or 3 are necessary.  In most others, he checks after you press return where Techniques 1 and 2 would suffice.  Following code after a _TEKey can be tedious.  I often set breakpoints to _BlockMove after I return from a _TEKey break.  Next, I check the area pointed to by register A0 after each _BlockMove is encountered until I find the sn which I entered.  Sometimes you get lucky and can treat a _BlockMove break like a _GetIText break from there.
  87.  
  88. Other techniques involve trapping _ModalDialog and finding where it will go when the user presses OK.  I rarely use that technique anymore as there may be user functions attached to _ModalDialog which process each keystroke and if not, _GetIText will put you further into the code.
  89.  
  90. "Where is it?" can be defined as "Where does it first reference anything I've typed into the dialog box?".  The sure-fire way to find it is to maintain the single stepping up to that point.
  91.  
  92. I'll be using Knot 3.6 as an example as its sn routine is not too extensive but still requires some thinking in its reversal.  The following code is found after using Technique 1 (and many single steps later):
  93.  
  94.          MOVEA.L 8(A7),A0                                                 
  95.          PUSH    #1  ; = StringToNum                                      
  96.          _Pack7                                                           
  97.          MOVEA.L 4(A7),A0                                                 
  98.          MOVE.L  D0,(A0)                                                  
  99.  
  100. This is the first occurrence of reference to the sn.  Here it converts the sn string into a number for further processing.  Now we're ready to proceed to question number two.
  101.  
  102.  
  103.  
  104. 2. WHAT DOES IT DO?
  105. ===================
  106.  
  107. The following are favorites to developers in checking your sn:
  108.  
  109. * Is the length correct?
  110. * Does it contain specific characters at predefined locations?
  111. * Does a calculation on some part of it result in the another part?
  112. * Does a calculation on other fields result in a part of it?
  113. * Does a lookup table on one part result in another?
  114. * Who cares what the user types?  (mission accomplished!)
  115.  
  116. This is the step where you need to get out your number two pencils and tablet of paper.  As you single step through the code, you must write down all that happens.  I tend to use tree diagrams stemming from the sn which I write at the top of the page with separation between each character.  Sometimes I need to draw arrows showing characters which are swapped.  Sometimes I write replacement characters above them.  Many times I have lines streaming down each character, or set of characters, resembling long term division but involving bitwise and/or other operators.  Use whatever works best for you but be sure to take down everything in a format legible at least to yourself, or you'll be sorry later.
  117.  
  118. Upon cruising through the code past the initial string-to-number routine, we find this:
  119.  
  120.          PEA     vjb_2(A6)
  121.          JSR     ITSGOOD           ; jump somewhere
  122.          POP.B   D0                ; retrieve the result code
  123.          BEQ.S   ljb_2             ; if result code = 0, jump to error alert
  124.          SUBQ    #2,A7
  125.          PEA     vjb_2(A6)
  126.          PEA     glob66(A5)
  127.          CLR.L   -(A7)
  128.          JSR     GETPREFS
  129.          POP.B   D0
  130.          MOVE.B  D0,vjb_1(A6)
  131.          MOVE.B  #1,glob43(A5)
  132.          SUBQ    #2,A7
  133.          PUSH    #$80
  134.          PEA     0
  135.          _Alert  ; (alertID:INTEGER; filterProc:ProcPtr):INTEGER 
  136.          POP     D0
  137.          EXT.L   D0
  138.          MOVE.L  D0,vjb_2(A6)
  139.          PUSH.L  $2988(A5)
  140.          JSR     DO_CLOSE
  141.          BRA.S   ljb_3
  142. ljb_2    SUBQ    #2,A7
  143.          PUSH    #$81
  144.          PEA     0
  145.          _Alert  ; (alertID:INTEGER; filterProc:ProcPtr):INTEGER 
  146.  
  147. At this point we know that "ITSGOOD" must NOT return a zero.
  148. Now let's see what lurks inside "ITSGOOD":
  149.  
  150. ITSGOOD  LINK    A6,#0
  151.          PUSH.L  A2
  152.          MOVEA.L param1(A6),A2
  153.          CLR.B   funRslt(A6)       ; Assume an invalid sn (prime a zero)
  154.          TST.L   (A2)              ; Rule 1
  155.          BEQ.S   liy_1             ;   "
  156.          MOVE.L  (A2),D0           ; Rule 2
  157.          ANDI.L  #$100,D0          ;   "
  158.          TST.L   D0                ;   "
  159.          BNE.S   liy_1             ;   "
  160.          CMPI.L  #$186A0,(A2)      ; Rule 3
  161.          BLT.S   liy_1             ;   "
  162.          MOVEQ   #31,D0            ; Rule 4
  163.          AND.L   (A2),D0           ;   "
  164.          ADDI.L  #$4531,D0         ;   "
  165.          MOVE.L  D0,D1             ;   "
  166.          MOVE.L  (A2),D0           ;   "
  167.          JSR     proc13            ;   " ==> proc13
  168.          CMPI.L  #$9D,D0           ; Rule 4 continued
  169.          BNE.S   liy_1             ;   "
  170.          MOVE.B  #1,funRslt(A6)    ; All checks are valid!
  171. liy_1    POP.L   A2
  172.          UNLK    A6
  173.          POP.L   (A7)
  174.          RTS     
  175.  
  176. proc13   TST.L   D1                ; Rule 4 continued
  177.          BGE.S   lao_1             ;   "
  178.          NEG.L   D1                
  179. lao_1    TST.L   D0                ;   "
  180.          BLT.S   lao_2             ;   "
  181.          JMP     proc12            ;   " ==> proc12
  182. lao_2    NEG.L   D0
  183.          JSR     proc12
  184.          NEG.L   D0
  185.          RTS     
  186.  
  187. proc12   MOVEM.L D2-D3,-(A7)       ; Rule 4 continued
  188.          MOVEQ   #2,D2             ;   "
  189.          JMP     data11-2(D2.W*2)  ;   " ==> data11
  190.  
  191. data11   BRA.S   lan_1             ; Rule 4 continued
  192.          DIVUL.L D1,D1:D0          ;   "
  193.          MOVE.L  D1,D0             ;   "
  194.          MOVEM.L (A7)+,D2-D3       ;   "
  195.          RTS                       ;   " ==> return back to ITSGOOD
  196.  
  197.  
  198. In viewing the code, we can now construct a set of rules which must be met for proper sn validation:
  199.  
  200. Rule 1 : sn must NOT be a zero
  201. Rule 2 : (sn & $100) = 0
  202. Rule 3 : sn >= $186A0
  203. Rule 4 : sn MOD ((sn & 31) + $4531) = $9D
  204.  
  205. Now we are ready to answer question three.
  206.  
  207.  
  208.  
  209. 3. HOW CAN IT BE REVERSED?
  210. ==========================
  211.  
  212. This question rarely has the same answer.  I've seen quite a few different techniques used in sn checksumming.  The main thing to remember here is, good notes = success.  I find it useful at this point to take a deep breath, view my notes, and ask myself "why?".  Why is it flipping every 5th bit or why does it repeat a certain pattern over and over again?  In answering these questions, you may find a simple way to repeat that capability in a more simplistic form.  Another thing to keep in mind is that there are often multiple ways to derive the same sn.  I will demonstrate this by providing two separate routines for reversing the Knot sn checksum.
  213.  
  214. In viewing the rules which were derived from question two, we find that rule 3 will allow us to disregard rule 1.  Rule 4 is the toughest one and will require us to dust off our old algebra books for solutions to simplification or take the easy way out.  First let's try the easy way, or better described as the "brute force" method:
  215.  
  216. FOR sn = $186A0 TO mymaxno
  217.   IF ((sn & $100)=0) AND (sn MOD ((sn & 31) + $4531)=$9D) THEN PRINT sn
  218. NEXT
  219.  
  220. Rule 1 : (Disregarded in lieu of rule 3)
  221. Rule 2 : Applied in the first half of the "IF" statement
  222. Rule 3 : Applied by the outer loop (sequentially increment sn from $186A0)
  223. Rule 4 : Applied in the second half of the "IF" statement
  224.  
  225. Although this method will work, it's slow.  Trying every number is never a good solution as the distance between valid numbers may be great.  So let's look a little deeper to find a better solution.
  226.  
  227. Let's see now:
  228.  
  229. Rule 4 : sn MOD ((sn & 31) + $4531) = $9D
  230.  
  231. ...is the same as saying:
  232.  
  233. Rule 4 : sn = x * ((sn & 31) + $4531) + $9D
  234.  
  235. Also, by sheer knowledge, we know that (sn & 31) can have only 32 possibilities (0-31).  So let's reinstate the formula where "p" may be any one of the 32 possibilities:
  236.  
  237. Rule 4 : sn = x * (p + $4531) + $9D
  238.  
  239. Now we can simply create an algorithm with nested loops.  The outer loop will control "x" and the inner loop will control each iteration of "p" (0-31):
  240.  
  241. FOR x=1 TO mymaxno
  242.   FOR p=0 TO 31
  243.     sn = x * (p + $4531) + $9D
  244.     IF sn >= $186A0 AND ((sn & $100) = 0) AND ((sn & 31) = p) THEN PRINT sn
  245.   NEXT
  246. NEXT
  247.  
  248. Notice the last part of the "IF" statement.  This is where we verify that p does, in fact, equal (sn & 31).
  249.  
  250. Using this second approach greatly reduces the time needed to generate numbers as we are skipping through all possibilities by leaps and bounds.
  251.  
  252. Now we are ready to answer the final question.
  253.  
  254.  
  255.  
  256. 4. DO THE GENERATED NUMBERS WORK?
  257. =================================
  258.  
  259. This is the easiest question to answer as you can simply type them in to check the results.  I recommend trying the lowest and highest sn followed by a few in between and a series "in a row".  If your notes and programming are good, they usually all work fine.  If there is a bug in your programming, they are usually all wrong or the lower and/or upper limits are wrong.
  260.  
  261. In this case, after running both algorithms, we arrive at the same results.  There is, of course, a noticeable difference in speed between them.
  262.  
  263.  
  264.  
  265. ENDING COMMENTS
  266. ===============
  267.  
  268. I've taken you on a journey through a simple situation.  There are, however, many more difficult routines being used in todays sn checksums.  You must keep in mind that nothing is impossible through determination.  No matter how you fold a piece of paper, it's always possible to unfold it once again.  Some folds may be tucked in deep and difficult to pull out.  There may be times you encounter hundreds of folds.  But no matter how much time is put into folding that sheet of paper, someone else can always unfold it.  There's no reason why you can't be that person!
  269.  
  270. Let the puzzles begin,
  271. =-BOOK-WORM->
  272.